/*
    This file is part of MOOPerformanceAssessment.

    MOOPerformanceAssessment is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    MOOPerformanceAssessment is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MOOPerformanceAssessment; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Authors: Thomas Voß, 2007
    Contact: thomas.voss.bochum@googlemail.com
*/

#include "../include/MOOPerformanceAssessmentFunctional.h"

#include <limits>

PointSet & operator+=( PointSet & a, const PointSet & b )
{
    for( unsigned i = 0; i < b.size(); i++ )
	a.push_back( b[i] );

    return( a );
}

int dominates( const Point & a, const Point & b )
{
    unsigned noOfObj = DIM( a );
    // set flag for calculation
    unsigned flag1 = 0;
    unsigned flag2 = 0;
    unsigned flag3 = 0;
    // calculation
    for (unsigned i = noOfObj; i--;) {
	if ( a[i] > b[i] ) {
	    flag1++;
	}
	else if (a[i] < b[i] ) {
	    flag3++;
	}
	else {
	    flag2++;
	}
    }

    // relationship
    if (flag1 + flag2 + flag3 != noOfObj) {
	return 0; // abnormal
    }
    else if (flag3 == noOfObj) {
	return 3; // a dominates b completely
    }
    else if (flag3 != 0 && flag1 == 0) {
	return 2; // a dominates b imcompletely
    }
    else if (flag2 == noOfObj) {
	return 1; // a equals b
    }
    else if (flag1 == noOfObj) {
	return -3; // b dominates a completely
    }
    else if (flag1 != 0 && flag3 == 0) {
	return -2; // b dominates a imcompletely
    }

    return -1; // trade off
}

void filter( PointSet & pointSet )
{
    PointSet::iterator ita, itb;

    int nErased = 0;

    ita = pointSet.begin(); 
    while( ita != pointSet.end() )
	{
	    itb = pointSet.begin();
	    while( itb != pointSet.end() )
		{
		    if( ita == itb )
			{
			    ++itb;
			    continue;
			}

		    int d = dominates( *ita, *itb );
		    
		    if( d == 3 )
			{
			    itb = pointSet.erase( itb );
			}
		    else
			++itb;
		}

		++ita;
	}
}

PointSet merge( const std::vector<PointSet> & pointSet )
{
    PointSet result;

    for( unsigned i = 0; i < pointSet.size(); i++ )
	for( unsigned j = 0; j < pointSet[i].size(); j++ )
	    result.push_back( pointSet[i][j] );

    return( result );
}

PointSet merge( const std::vector<std::vector<PointSet> > & pointSet )
{
    PointSet result;

    for( unsigned i = 0; i < pointSet.size(); i++ )
	result += merge( pointSet[i] );
			  
    return( result );
}

void normalize( PointSet & pointSet, const Point & reference )
{
    Point min( reference.size(), std::numeric_limits<double>::max() );
    Point max( reference.size(), std::numeric_limits<double>::min() );
    
    for( unsigned i = 0; i < pointSet.size(); i++ )
	for( unsigned j = 0; j < DIM( reference ); j++ )
	    {
		min[j] = std::min( min[j], pointSet[i][j] );
		max[j] = std::max( max[j], pointSet[i][j] );
	    }

    normalize( pointSet, min, max, reference );
}

void normalize( PointSet & pointSet, 
		const Point & min, 
		const Point & max, 
		const Point & reference )
{
    for( unsigned i = 0; i < pointSet.size(); i++ )
	for( unsigned j = 0; j < DIM( reference ); j++ )
	    pointSet[i][j] = reference[j] * (pointSet[i][j] - min[j]) / ( max[j] - min[j] );    
}
